package com.pucong.gitee.database.backup.business.unRelational.redis.service;

import com.pucong.gitee.database.backup.business.sys.mapper.SysFileMapper;
import com.pucong.gitee.database.backup.common.entity.redis.KeyBean;
import com.pucong.gitee.database.backup.common.entity.redis.ZTreeBean;
import com.pucong.gitee.database.backup.common.entity.redis.dto.RedisValUpdateDto;
import com.pucong.gitee.database.backup.common.entity.sys.SysFile;
import com.pucong.gitee.database.backup.common.entity.sys.UserJwt;
import com.pucong.gitee.database.backup.common.selfenum.RedisDataType;
import com.pucong.gitee.database.backup.common.selfenum.RedisTreeType;
import com.pucong.gitee.database.backup.configuration.exception.BusinessException;
import com.pucong.gitee.database.backup.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class DataSinglesServiceImpl implements DataSinglesService {

    @Autowired
    private SysFileMapper sysFileMapper;

    @Autowired
    private AutoRedisConnectService autoRedisConnectService;

    @Override
    public List<ZTreeBean> treeInit(String id) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        List<ZTreeBean> treeList = new ArrayList<>();
        if (null != jedis) {
            String role = RedisUtil.getInfo(jedis, "server");
            boolean isCluster = role.contains("redis_mode:cluster");
            for (int i = 0; i < RedisUtil.getDbCount(jedis); i++) {
                long dbSize;
                if (i > 0 && isCluster) {
                    break;
                }
                if (isCluster) {
                    dbSize = RedisUtil.dbSize(jedis, null);
                } else {
                    dbSize = RedisUtil.dbSize(jedis, i);
                }
                ZTreeBean zTreeBean = new ZTreeBean();
                zTreeBean.setId(UUID.uuid());
                zTreeBean.setName("DB" + i + " (" + dbSize + ")");
                zTreeBean.setType(RedisTreeType.db);
                zTreeBean.setCount(dbSize);
                zTreeBean.setIndex(i);
                treeList.add(zTreeBean);
            }
        }
        jedis.close();
        return treeList;
    }

    @Override
    public ZTreeBean likeInit(String id, int index, String pattern) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        long keysCount = RedisUtil.getKeysCount(jedis, index, pattern);
        jedis.close();
        ZTreeBean ztreeBean = new ZTreeBean();
        ztreeBean.setId(UUID.uuid());
        ztreeBean.setName("DB" + index + " (" + keysCount + ")");
        ztreeBean.setType(RedisTreeType.db);
        ztreeBean.setCount(keysCount);
        ztreeBean.setIndex(index);
        return ztreeBean;
    }

    @Override
    public List<ZTreeBean> treeData(String id, int index, String pattern) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        List<ZTreeBean> keyTree = RedisUtil.getKeyTree(jedis, index, id, pattern);
        jedis.close();
        return keyTree;
    }

    @Override
    public List<ZTreeBean> pageData(String id, int index, int page, String pattern) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        List<ZTreeBean> keyPage = RedisUtil.getKeyPage(jedis, index, page, id, pattern);
        jedis.close();
        return keyPage;
    }

    @Override
    public KeyBean keysData(String id, int index, String keys, String order) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        if (!RedisUtil.existsKey(jedis, index, keys)) {
            throw new BusinessException("该key不存在");
        }
        KeyBean keyInfo = RedisUtil.getKeyInfo(jedis, index, keys, order);
        jedis.close();
        keyInfo.setTypeEnum(RedisDataType.findEnumByName(keyInfo.getType()));
        return keyInfo;
    }

    @Override
    public Boolean renameKey(String id, int index, String oldKey, String newKey) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        if (!RedisUtil.existsKey(jedis, index, oldKey)) {
            throw new BusinessException("该key不存在");
        }
        if (RedisUtil.existsKey(jedis, index, newKey)) {
            throw new BusinessException("该KEY已存在");
        }
        RedisUtil.renameKey(jedis, index, oldKey, newKey);
        jedis.close();
        return true;
    }

    @Override
    public Boolean recoverDb(String id, int index, String fileId) {
        UserJwt loginUser = UserRequest.getLoginUser();
        SysFile sysFile = sysFileMapper.selectById(fileId);
        if (null != sysFile) {
            Jedis jedis = autoRedisConnectService.getJedis(id);
            RedisUtil.recoveKey(jedis, index, FileUtil.readFileToString(sysFile.getPath()));
            jedis.close();
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean backupDb(String id, int index, String pattern) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
        String fileName = "redisplus-dbdata-" + format.format(new Date()) + ".bak";
        String filePath = ApplicationContextUtil.getUploadPath() + "/" + fileName;
        boolean flag = FileUtil.writeStringToFile(filePath, RedisUtil.backupKey(jedis, index, pattern));
        jedis.close();
        if (flag) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean removeKey(String id, int index) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        jedis.select(index);
        jedis.flushDB();
        jedis.close();
        return true;
    }

    @Override
    public Boolean insertKey(String id, int index, RedisDataType type, String key, String val, long time, double score) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        //1:set,2:zset,3:list,4:hash 5str
        switch (type) {
            case set:
                RedisUtil.insertSet(jedis, index, key, val);
                break;
            case zset:
                RedisUtil.insertZset(jedis, index, key, val, score);
                break;
            case list:
                RedisUtil.insertList(jedis, index, key, val);
                break;
            case hash:
                String[] valArray = val.split(":");
                String mapKey = valArray[0];
                String mapVal = valArray[1];
                RedisUtil.insertHash(jedis, index, key, mapKey, mapVal);
                break;
            case str:
                RedisUtil.insertStr(jedis, index, key, val);
                break;
        }
        if (time != -1) {
            RedisUtil.retimeKey(jedis, index, key, time);
        }
        jedis.close();

        return true;
    }

    @Override
    public Boolean updateVal(String id, RedisValUpdateDto dto) {
        Jedis jedis = autoRedisConnectService.getJedis(id);
        RedisDataType type = dto.getType();
        Integer index = dto.getIndex();
        String key = dto.getKey();
        if (!RedisUtil.existsKey(jedis, index, key)) {
            throw new BusinessException("该key不存在");
        }
        //1:set,2:zset,3:list,4:hash
        switch (type) {
            case set:
                String oldVal = dto.getOldVal();
                String newVal = dto.getNewVal();
                RedisUtil.deleteSet(jedis, index, key, oldVal);
                RedisUtil.insertSet(jedis, index, key, newVal);
                break;
            case zset:
                String oldZval = dto.getOldVal();
                String newZval = dto.getNewVal();
                double score = dto.getScore();
                RedisUtil.deleteZset(jedis, index, key, oldZval);
                RedisUtil.insertZset(jedis, index, key, newZval, score);
                break;
            case list:
                Integer itemIndex = dto.getItemIndex();
                String val = dto.getNewVal();
                RedisUtil.updateList(jedis, index, key, itemIndex, val);
                break;
            case hash:
                String oldMapKey = dto.getOldKey();
                String newMapKey = dto.getNewKey();
                String newMapVal = dto.getNewVal();
                RedisUtil.deleteHash(jedis, index, key, oldMapKey);
                RedisUtil.insertHash(jedis, index, key, newMapKey, newMapVal);
                break;
        }
        jedis.close();
        return true;
    }

    @Override
    public Boolean deleteVal(String id, int index, RedisDataType type, String key, String val) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        if (!RedisUtil.existsKey(jedis, index, key)) {
            throw new BusinessException("该key不存在");
        }
        //1:set,2:zset,3:list,4:hash
        switch (type) {
            case set:
                RedisUtil.deleteSet(jedis, index, key, val);
                break;
            case zset:
                RedisUtil.deleteZset(jedis, index, key, val);
                break;
            case list:
                long keyIndex = Long.parseLong(val);
                RedisUtil.deleteList(jedis, index, key, keyIndex);
                break;
            case hash:
                String mapKey = val;
                RedisUtil.deleteHash(jedis, index, key, mapKey);
                break;
        }
        jedis.close();
        return true;
    }

    @Override
    public Boolean insertVal(String id, int index, RedisDataType type, String key, String val, double score) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        if (!RedisUtil.existsKey(jedis, index, key)) {
            throw new BusinessException("该key不存在");
        }
        //1:set,2:zset,3:list,4:hash
        switch (type) {
            case set:
                RedisUtil.insertSet(jedis, index, key, val);
                break;
            case zset:
                RedisUtil.insertZset(jedis, index, key, val, score);
                break;
            case list:
                RedisUtil.insertList(jedis, index, key, val);
                break;
            case hash:
                String[] valArray = val.split(":");
                String mapKey = valArray[0];
                String mapVal = valArray[1];
                RedisUtil.insertHash(jedis, index, key, mapKey, mapVal);
                break;
        }
        jedis.close();
        return true;
    }

    @Override
    public Boolean updateStr(String id, int index, String key, String val) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        if (!RedisUtil.existsKey(jedis, index, key)) {
            throw new BusinessException("该key不存在");
        }
        RedisUtil.updateStr(jedis, index, key, val);
        jedis.close();
        return true;
    }

    @Override
    public Boolean retimeKey(String id, int index, String key, long time) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        if (!RedisUtil.existsKey(jedis, index, key)) {
            throw new BusinessException("该key不存在");
        }
        RedisUtil.retimeKey(jedis, index, key, time);
        jedis.close();
        return true;
    }

    @Override
    public Boolean deleteKey(String id, int index, String key) {
        UserJwt loginUser = UserRequest.getLoginUser();
        Jedis jedis = autoRedisConnectService.getJedis(id);
        if (!RedisUtil.existsKey(jedis, index, key)) {
            throw new BusinessException("该key不存在");
        }
        RedisUtil.deleteKey(jedis, index, key);
        jedis.close();
        return true;
    }
}
